package cn.jbolt.wechat.common.mp;


import cn.hutool.core.util.StrUtil;
import cn.jbolt.core.base.config.JBoltConfig;
import cn.jbolt.wechat.model.WechatUser;
import cn.jbolt.wechat.service.JBoltWechatConfigService;
import cn.jbolt.wechat.service.JBoltWechatMenuEventProcesser;
import cn.jbolt.wechat.service.JBoltWechatReplyContentService;
import cn.jbolt.wechat.service.JBoltWechatUserService;
import com.jfinal.aop.Aop;
import com.jfinal.aop.Inject;
import com.jfinal.kit.HttpKit;
import com.jfinal.kit.StrKit;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * 微信推送来的消息路由
 */
public class WechatMpMsgRouter {

    public static final WechatMpMsgRouter me = new WechatMpMsgRouter();

    private  WxMpMessageRouter router = new WxMpMessageRouter(WechatMpContext.SERVICE);

    private JBoltWechatConfigService wechatConfigService = Aop.get(JBoltWechatConfigService.class);
    @Inject
    private JBoltWechatReplyContentService wechatReplyContentService = Aop.get(JBoltWechatReplyContentService.class);
    @Inject
    private JBoltWechatMenuEventProcesser wechatMenuEventProcesser = Aop.get(JBoltWechatMenuEventProcesser.class);
    @Inject
    private JBoltWechatUserService wechatUserService = Aop.get(JBoltWechatUserService.class);

    private WechatMpMsgRouter(){
        addEventHandler(router);

        addTextHandler(router);

        addDefaultHandler(router);
    }

    /**
     * 添加默认的路由映射
     * @param router
     */
    private void addDefaultHandler(WxMpMessageRouter router) {
        router.rule().async(false).handler(new WechatMpMessageHandler(msg -> {
            WxMpXmlOutMessage res = wechatReplyContentService.getWechcatDefaultOutMsg(WechatMpContext.getCurrentAppId(), msg.getFromUser());
            if (res == null) {
                return WechatMpContext.DEFAULT_MESSAGE;
            }
            return res;
        })).end();
    }


    /**
     * 当接收到微信推送过来的事件时，做什么处理
     * @param router
     */
    private  void addEventHandler(WxMpMessageRouter router) {
        //关注
        router.rule().async(false)
                .msgType("event").event("subscribe")
                .handler(new WechatMpMessageHandler((msg) -> {
                    String openId = msg.getFromUser();
                    return handleSubscribe(openId);
                }))
                .end();
        //取消关注
        router.rule()
                .msgType("event").event("unsubscribe")
                .handler(new WechatMpMessageHandler((msg) -> {
                    String openId = msg.getFromUser();
                    return handleCancelSubscribe(openId);
                }))
                .end();
        // 上报地理位置
        router.rule().async(false)
                .msgType("event").event("LOCATION")
                .handler(new WechatMpMessageHandler((msg) -> {
                    String openId = msg.getFromUser();
                    return handleLocation(msg.getLatitude(), msg.getLongitude(), msg.getPrecision());
                }))
                .end();

        // 菜单事件

        router.rule().async(false)
                .msgType("event")
                .handler(new WechatMpMessageHandler(msg -> {
                    return handleMenuEvent(msg);
                })).end();
    }

    private WxMpXmlOutMessage handleMenuEvent(WxMpXmlMessage msg) {
        if(JBoltConfig.DEV_MODE) {
            System.out.println("菜单：Event:" + msg.getEvent());
            System.out.println("菜单：EventKey:" + msg.getEventKey());
            System.out.println("菜单：MsgType:" + msg.getMsgType());
            System.out.println("菜单：openId:" + msg.getFromUser());
//			System.out.println("菜单：MenuId:" + inMenuEvent.getMenuId());
            System.out.println("菜单：公众平台原始ID:" + msg.getToUser());
        }
        if (msg.getEvent().matches("CLICK|VIEW|scancode_push|scancode_waitmsg|pic_sysphoto|pic_photo_or_album|pic_weixin|location_select|media_id|view_limited|view_miniprogram")) {

            return wechatMenuEventProcesser.process(WechatMpContext.getCurrentAppId(), msg);
        } else {
            return null;
        }

    }

    /**
     * 处理位置上报事件
     * @param latitude
     * @param longitude
     * @param precision
     * @return
     */
    private WxMpXmlOutMessage handleLocation(Double latitude, Double longitude, Double precision) {
        return WxMpXmlOutMessage.TEXT().content(StrUtil.format("收到您发过来的位置信息: 经度 {}，纬度 {} 精度 {}", longitude ,latitude, precision )).build();
    }


    /**
     * 处理关注
     * @param openId
     * @return
     */
    private  WxMpXmlOutMessage handleSubscribe(String openId) {
        WxMpXmlOutMessage outMsg = wechatReplyContentService.getWechcatSubscribeOutMsg(WechatMpContext.getCurrentAppId(),openId);
        //微信用户表里需要同步用户信息和关注状态
        wechatUserService.syncSubscribeUserInfo(WechatMpContext.getCurrentAppId(),openId);
        return outMsg;
    }

    /**
     * 处理取消关注
     * @param openId
     * @return
     */
    private  WxMpXmlOutMessage handleCancelSubscribe(String openId) {
        //更新微信用户关注状态
        wechatUserService.updateUserInfo(WechatMpContext.getCurrentAppId(),openId, WechatUser.SUBSCRIBE, false);
        return null;
    }



    /**
     * 当接收到微信推送过来的文字消息时，做什么处理
     * @param router
     */
    private  void addTextHandler(WxMpMessageRouter router) {
        router.rule().async(false)
                .msgType("text")
                .handler(new WechatMpMessageHandler((msg) -> {
                    String openId = msg.getFromUser();
                    WxMpXmlOutMessage outMsg = wechatReplyContentService.getWechcatKeywordsOutMsg(WechatMpContext.getCurrentAppId(), msg.getContent(), openId);
                    return outMsg;
                }))
                .end();
    }


    /**
     * 根据请求执行路由
     * @param request
     * @return
     */
    public  String route(HttpServletRequest request) {
        WxMpXmlMessage fromMsg = getMessage(request);
        //解析消息的时候，做了特殊处理，如果消息是加密消息，会将encrypt的值设置为1
        boolean encrypt = Objects.equals(fromMsg.getEncrypt(), "1");
        WxMpXmlOutMessage outMsg = router.route(fromMsg);
        if (outMsg == null) {
            return "";
        }
        outMsg.setFromUserName(fromMsg.getToUser());
        outMsg.setToUserName(fromMsg.getFromUser());
        outMsg.setCreateTime(System.currentTimeMillis());
        if (encrypt) {
            return outMsg.toEncryptedXml(WechatMpContext.SERVICE.getWxMpConfigStorage());
        }
        return outMsg.toXml();
    }

    /**
     * 从请求体中获取消息体
     * @param request
     * @return
     */
    private  WxMpXmlMessage getMessage(HttpServletRequest request) {
        String inMsgXml = HttpKit.readData(request);
        if (StrKit.isBlank(inMsgXml)) {
            throw new RuntimeException("请不要在浏览器中请求该连接,调试请查看WIKI:http://git.oschina.net/jfinal/jfinal-weixin/wikis/JFinal-weixin-demo%E5%92%8C%E8%B0%83%E8%AF%95");
        }
        if (JBoltConfig.DEV_MODE) {
            System.out.println("接收消息:");
            System.out.println(inMsgXml);
        }
        String timestamp = getPara(request,"timestamp");
        String nonce = getPara(request,"nonce");
        String msg_signature = getPara(request,"msg_signature");
        String encrypt_type = getPara(request,"encrypt_type");
        if (msg_signature == null) {
            //明文模式
            return WxMpXmlMessage.fromXml(inMsgXml);
        }
        WxMpXmlMessage msg = WxMpXmlMessage.fromEncryptedXml(inMsgXml, WechatMpContext.SERVICE.getWxMpConfigStorage(), timestamp, nonce, msg_signature);
        //这里做了特殊处理，标记该条消息是加密过的
        msg.setEncrypt("1");
        return msg;
    }

    private  String getPara(HttpServletRequest request, String name) {
        String result = request.getParameter(name);
        return result != null && result.length() != 0 ? result : null;
    }
}
